<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/vue.js"></script>
    <style>
        .a,
        .b,
        .c,
        .d {
            border: 1px dashed #333;
            padding: 20px;
            margin: 5px 0;
        }
    </style>
</head>

<body>
    <div id="app">
        <!-- <count-down></count-down>
        <count-down></count-down>
        <count-down></count-down>
        <aaa-bbb></aaa-bbb> -->

        <count-down></count-down>
        <comp-a></comp-a>
        <comp-b></comp-b>
        <!-- <comp-b></comp-b>
        <comp-c></comp-c>
        <comp-d></comp-d> -->
    </div>
</body>
<script>
    // 组件: 是一个可复用的Vue实例  => 将Vue中可重复使用的功能提取出来,封装为组件 

    // 如何封装组件? 
    // 1. 全局组件  => 借助 Vue.component(name,options) 方法(构造函数Vue的静态方法)
    // name 组件名称, 复杂的组件名,一般建议使用中划线命名法(count-down  -> Vue2),也可以使用大驼峰式命名法(CountDown -> Vue3)
    // options  组件的配置项 data methods computed watch 生命周期及钩子函数

    // 优点: 
    // 全局组件只要注册一次, 可以在所有组件实例中使用

    // 缺点:
    // 1. 全局组件一经注册,无论项目中是否使用, 都会打包到项目的源码中  => 如果注册组件不使用, 代码冗余
    // 2. 使用全局组件,会造成组件的层级关系比较混乱


    // 2. 局部组件
    // 使用时才会被注册

    // 优点:
    // 父组件需要先注册子组件才能使用  => 依赖关系比较明确
    // 如果组件注册之后没有被使用, 项目打包过程中,会作为冗余代码删除

    // 缺点:
    // 如果一个局部组价被多个组件引用,需要注册多次




    // 局部组件

    // 组件的配置对象 
    var CountDown = {
        // name: "count-down",
        data: function () {
            return {
                countTime: 100,  //倒计时的时间(s)
                timer: null,
            }
        },
        template: `<div class="count-down">
            {{beauty(hour)}}:{{beauty(min)}}:{{beauty(sec)}}
        </div>`,
        methods: {
            beauty(num) {
                return num < 10 ? "0" + num : num;
            },
            countDownHandler() {
                clearInterval(this.timer);
                this.timer = setInterval(() => {
                    this.countTime--;
                }, 1000)
            }
        },
        computed: {
            // 将倒计时的时间换算为天时分秒
            day: function () {
                return parseInt(this.countTime / (24 * 60 * 60));
            },
            hour: function () {
                // 总的时间 % 一天的时间 =>  不满一天的时间
                // 不满一天的时间 / 一小时
                return parseInt(this.countTime % (24 * 60 * 60) / (60 * 60))
            },
            min: function () {
                // 不满一小时 / 一分钟
                return parseInt(this.countTime % (60 * 60) / 60);
            },
            sec: function () {
                // 不满一小时 / 一分钟
                return this.countTime % 60;
            },
        },
        beforeCreate() {
            console.log("子组件count-down:beforeCreate");
        },
        created() {
            console.log("子组件count-down:created");
        },
        beforeMount() {
            console.log("子组件count-down:beforeMount");
        },
        mounted() {
            this.countDownHandler();
            console.log("子组件count-down:mounted", this);
        },
    }


    var CompC = {
        data() {
            return {

            }
        },
        template: `<div class="c">
                <div>我是组件C</div>
            </div>`
    }


    var CompB = {
        data() {
            return {

            }
        },
        template: `<div class="b">
                <div>我是组件B</div>
                <comp-c></comp-c>
            </div>`,
        components: {
            CompC
        }
    }

    var CompA = {
        data() {
            return {

            }
        },
        template: `<div class="a">
                <div>我是组件A</div>
                <comp-b></comp-b>
            </div>`,
        components: {
            CompB,
        }
    }




    var CompD = {
        data() {
            return {

            }
        },
        template: `<div class="d">
                <div>我是组件D</div>
            </div>`
    }



    // 如何使用组件?
    // 1. 封装的组件可以在其他组件中使用 (组件的层级关系:  父组件 子组件  同级组件)
    // 2. 将组件作为自定义标签使用 (父组件在模版解析过程中会判断自定义标签是否已经作为组件注册, 如果没有就会报错)  => 全局组件,直接对应自定义标签使用, 局部组件,先注册在使用


    // 组件封装注意:
    // 1. data选项, 要求是返回对象的函数 => 每个组件中的数据都是独立的
    // 2. 单个根元素(Vue2)     => Vue3可以有多个同级元素
    // 3. 单项数据流


    // 组件的生命周期_初始化
    // 首先根组件先进行初始化渲染, 一般情况下,将模版解析为虚拟DOM,此时如果遇到自定义标签,会先判断该标签是否已经作为组件注册, 如果已经注册,就会触发子组件的初始化渲染(根组件等在子组件此时处于等待状态) ,子组件也会编译模版为虚拟DOM,将其解析为真实DOM,和对应的自定义标签绑定(elm:xxx),等子组件解析完毕,父组件接续向后解析, 将模版中内容解析为虚拟DOM, 渲染为真实DOM, 更新视图



    // 根组件
    var app = new Vue({
        el: "#app",
        data: {
            count: 1,
        },
        components: {
            // 对象的键名 -> 被注册的组件名
            // 对象的健值 -> 被注册的组件的options配置
            // CountDown: CountDown,
            "count-down": CountDown,
            CompA: CompA,
            CompB: CompB,
        }
    })








</script>

</html>